package com.winexpress.product;

import com.winexpress.util.SessionAttributes;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.ws.WebServiceRef;
import com.alchemyapi.api.AlchemyAPI;
import com.winexpress.util.Log;
import java.io.StringWriter;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;

@WebServlet(name = "Products", urlPatterns = {"/products/*"})
public class Products extends HttpServlet {

    @WebServiceRef(wsdlLocation = "WEB-INF/wsdl/localhost_8080/WineXpress-war/ProductManagementWS.wsdl")
    private ProductManagementWS_Service service;

    @WebServiceRef(wsdlLocation = "WEB-INF/wsdl/localhost_8080/WineXpress-war/RatingManagementWS.wsdl")
    private RatingManagementWS_Service service_1;

    @WebServiceRef(wsdlLocation = "WEB-INF/wsdl/localhost_8080/WineXpress-war/CommentManagementWS.wsdl")
    private CommentManagementWS_Service service_2;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SAXException, ParserConfigurationException, XPathExpressionException {
        response.setContentType("text/html;charset=UTF-8");

        //Get Product ID
        String id = request.getParameter("id");
        Long wid = Long.parseLong(id);

        HttpSession session = request.getSession();
        String user = null;
        user = (String) session.getAttribute(SessionAttributes.USER_ID);

        CommentManagementWS port3 = service_2.getCommentManagementWSPort();
        RatingManagementWS port2 = service_1.getRatingManagementWSPort();
        ProductManagementWS port = service.getProductManagementWSPort();

        //If this is an rating request
        String star = request.getParameter("star");
        if (star != null) {
            if (user != null) {
                Long userID = Long.parseLong(user);
                int rate = Integer.parseInt(star);
                RatingMessage outMessage = new RatingMessage();
                outMessage.setUid(userID);
                outMessage.setWid(wid);
                outMessage.setRating(rate);
                port2.addRating(outMessage);
                request.setAttribute("alert1", "1");
            } else {
                request.setAttribute("alert2", "1");
            }
        }

        //If this is an comment request
        String comment = request.getParameter("comment");
        if (comment != null) {
            if (user != null) {
                Long userID = Long.parseLong(user);
                String userInput = request.getParameter("userinput");

                AlchemyAPI alchemyObj = AlchemyAPI.GetInstanceFromString("3e31f261cb8a2765b081848ee34e72ec61648bc3");
                Document doc = alchemyObj.TextGetTextSentiment(userInput + ":input");
                NodeList nList = doc.getElementsByTagName("docSentiment");
                Node node = nList.item(0);
                Element eElement = (Element) node;
                String nature = eElement.getElementsByTagName("type").item(0).getTextContent();

                Comment outComment = new Comment();
                outComment.setId(userID);
                outComment.setWid(wid);
                outComment.setComment(userInput);
                outComment.setNature(nature);
                port3.addComment(outComment);

                if (nature.equals("negative")) {
                    Log.info("userID = " + SessionAttributes.USER_ID + " sensitive words in the comment.");
                }
                request.setAttribute("alert3", "1");
            } else {
                request.setAttribute("alert4", "1");
            }
        }

        if (request.getParameter("addtocart") != null) {
            String items = (String) session.getAttribute("items");

            if (items == null) {
                items = "";
            }

            String[] array = items.split("\\;");

            if (array.length == 1) {
                items = "";
                items = items + request.getParameter("id") + ";";
                items = items + request.getParameter("qty") + ";";
            } else {
                boolean flag = false;
                for (int i = 0; i < array.length; i = i + 2) {
                    System.out.println(i + " " + array[i]);
                    if (array[i].equals(request.getParameter("id"))) {
                        Integer sum = Integer.parseInt(array[i + 1]) + Integer.parseInt(request.getParameter("qty"));
                        array[i + 1] = sum.toString();
                        flag = true;
                    }
                }

                items = "";
                for (int i = 0; i < array.length; i = i + 1) {
                    items = items + array[i] + ";";
                }
                if (flag == false) {
                    items = items + request.getParameter("id") + ";";
                    items = items + request.getParameter("qty") + ";";
                }
            }
            session.setAttribute("items", items);
            request.setAttribute("alert5", "1");
        }

        //Get Product Info
        Wine wine = port.getWine(wid);

        //Set Product Details
        request.setAttribute("country", wine.country);
        request.setAttribute("description", wine.description);
        request.setAttribute("name", wine.name);
        request.setAttribute("price", wine.price);
        request.setAttribute("producer", wine.producer);
        request.setAttribute("region", wine.region);
        request.setAttribute("sku", wine.stock);
        request.setAttribute("varietal", wine.varietal);
        request.setAttribute("vintage", wine.vintage);
        request.setAttribute("volume", wine.volume);
        request.setAttribute("image", wine.imageUrl);
        request.setAttribute("wid", wid);
        request.setAttribute("price", wine.getPrice());
        request.setAttribute("discount", wine.getDiscount());

        //Get Number of Items in Cart
        int count = 0;

        if (session.getAttribute("items") == null) {
            int i = 0;
            request.setAttribute("itemsnum", i);
        } else {
            String items = (String) session.getAttribute("items");
            String[] array = items.split("\\;");
            for (int i = 1; i < array.length; i = i + 2) {
                count = count + Integer.parseInt(array[i]);
            }
            request.setAttribute("itemsnum", count);
        }
        //End Number of Items in Cart

        DecimalFormat df = new DecimalFormat("#.#");
        request.setAttribute("average", df.format(port2.getAverageRating(wid)));

        List<Comment> commentsObj = new ArrayList<Comment>();
        commentsObj = port3.getProductComment(wid);
        request.setAttribute("commentsObj", commentsObj);

        List<String> comments = new ArrayList<String>();
        for (Comment c : port3.getProductComment(wid)) {
            comments.add(c.getComment());
        }
        request.setAttribute("comments", comments);

        //Dispatch return
        RequestDispatcher dispatcher;
        ServletContext servletContext = getServletContext();
        String page = request.getPathInfo();
        page = page.substring(1);
        dispatcher = servletContext.getNamedDispatcher(page);
        if (dispatcher == null) {
            dispatcher = servletContext.getNamedDispatcher("Error");
        }
        dispatcher.forward(request, response);
    }

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SAXException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XPathExpressionException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SAXException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        } catch (XPathExpressionException ex) {
            Logger.getLogger(Products.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private Wine getWine(long id) {
        // Note that the injected javax.xml.ws.Service reference as well as port objects are not thread safe.
        // If the calling of port operations may lead to race condition some synchronization is required.
        com.winexpress.product.ProductManagementWS port = service.getProductManagementWSPort();
        return port.getWine(id);
    }

    private double getAverageRating(long wid) {
        // Note that the injected javax.xml.ws.Service reference as well as port objects are not thread safe.
        // If the calling of port operations may lead to race condition some synchronization is required.
        com.winexpress.product.RatingManagementWS port = service_1.getRatingManagementWSPort();
        return port.getAverageRating(wid);
    }

    private java.util.List<com.winexpress.product.Comment> getProductComment(long wid) {
        // Note that the injected javax.xml.ws.Service reference as well as port objects are not thread safe.
        // If the calling of port operations may lead to race condition some synchronization is required.
        com.winexpress.product.CommentManagementWS port = service_2.getCommentManagementWSPort();
        return port.getProductComment(wid);
    }

    // utility method
    private static String getStringFromDocument(Document doc) {
        try {
            DOMSource domSource = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);

            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, result);

            return writer.toString();
        } catch (TransformerException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private Long addRating(com.winexpress.product.RatingMessage inMessage) {
        // Note that the injected javax.xml.ws.Service reference as well as port objects are not thread safe.
        // If the calling of port operations may lead to race condition some synchronization is required.
        com.winexpress.product.RatingManagementWS port = service_1.getRatingManagementWSPort();
        return port.addRating(inMessage);
    }

    private Long addComment(com.winexpress.product.Comment inComment) {
        // Note that the injected javax.xml.ws.Service reference as well as port objects are not thread safe.
        // If the calling of port operations may lead to race condition some synchronization is required.
        com.winexpress.product.CommentManagementWS port = service_2.getCommentManagementWSPort();
        return port.addComment(inComment);
    }
}
